﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using 卷书.UserControls;

namespace 卷书.Utils
{
    public class LibraryStream
    {
        private static string[] Nodes = new[] { "CreateDate", "Files" };
        private static string[] LibraryFileNodes = new[] { "filename", "filepath", "importdate", "tags", "descriptions" };
        private XmlDocument XmlDoc;
        private Library Library;

        private string Root = "Libraries";
        private bool CreateRoot = false;



        private string _Path = ""; //文件的绝对路径

        public string Path
        {

            get
            {
                return _Path;
            }
            set
            {
                _Path = value;
            }

        }



        public LibraryStream(Library library, string filepath)
        {
            Path = filepath;
            Library = library;
            InitXML();
        }


        public LibraryStream(string filename)
        {
            Path = filename;
        }

        public List<Library> Read()
        {
            List<Library> result = new List<Library>();


            if (File.Exists(Path))
            {
                XmlDoc = new XmlDocument();
                XmlDoc.Load(Path);
                foreach (var item in ReadAllName())
                {
                    result.Add(new Library() { Name = item });
                }
            }
            return result;
        }




        public void InitXML(bool createrootonly = false)
        {
            XmlDoc = new XmlDocument();
            if (File.Exists(Path))
            {
                //是否是标准的 xml 格式
                try
                {
                    XmlDoc.Load(Path);
                }
                catch (Exception ex)
                {
                    Logger.LogF(ex);
                    CreateRoot = true;
                }
            }
            else
            {
                CreateRoot = true;
            }


            //根节点
            if (CreateRoot)
            {
                XmlNode header = XmlDoc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
                XmlDoc.AppendChild(header);
                var xm = XmlDoc.CreateElement(Root);
                XmlDoc.AppendChild(xm);
            }

            if (!createrootonly)
            {
                XmlElement re = XmlDoc.DocumentElement;
                XmlNode nd = XmlDoc.SelectSingleNode($"/Libraries/Library[@Name='{Library.Name}']");
                if (nd == null)
                {
                    //不存在该节点
                    XmlElement XE = XmlDoc.CreateElement("Library");
                    XE.SetAttribute("Name", Library.Name);
                    re.AppendChild(XE);
                }


                foreach (var item in typeof(Library).GetProperties())
                {
                    XmlElement rootElement = XmlDoc.DocumentElement;
                    XmlNode node = XmlDoc.SelectSingleNode($"/Libraries/Library[@Name='{Library.Name}']");
                    //子子节点
                    foreach (var Node in Nodes)
                    {
                        XmlNode xn = XmlDoc.SelectSingleNode($"/Libraries/Library[@Name='{Library.Name}']/{Node}");
                        if (xn == null)
                        {
                            XmlElement xe = XmlDoc.CreateElement(Node);
                            if (Node == "CreateDate")
                            {
                                if (Library.CreateDate.Year != 1900)
                                {
                                    xe.InnerText = Library.CreateDate.ToString("yyyy-MM-dd HH:mm:ss");
                                }
                            }

                            else
                                xe.InnerText = "";
                            node.AppendChild(xe);
                        }
                    }
                }
            }




            try
            {
                XmlDoc.Save(Path);
            }
            catch (XmlException ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void SaveLibrary()
        {
            if (Library.Name == "") return;
            foreach (var Node in Nodes)
            {
                XmlNode xn = XmlDoc.SelectSingleNode($"/Libraries/Library[@Name='{Library.Name}']/{Node}");
                //if (xn != null)
                //{
                //    System.Reflection.PropertyInfo propertyInfo = type.GetProperty(Node);
                //    xn.InnerText = propertyInfo.GetValue(server).ToString();
                //}
            }
            Save();
        }




        private void Save()
        {
            XmlDoc.Save(Path);
        }

        public List<string> ReadAllName()
        {
            List<string> result = new List<string>();
            XmlNodeList nodes = XmlDoc.SelectNodes($"/Libraries/Library");
            if (nodes != null && nodes.Count > 0)
            {
                foreach (XmlNode item in nodes)
                {
                    if (!result.Contains(item.Attributes["Name"].Value))
                        result.Add(item.Attributes["Name"].Value);
                }
            }
            return result;
        }

        public string ReadByName(string name, string node)
        {
            XmlNode x1 = XmlDoc.SelectSingleNode($"/Libraries/Library[@Name='{name}']/{node}");
            if (x1 != null) return x1.InnerText;
            return "";
        }


        public static List<LibraryFile> Read(string name)
        {
            List<LibraryFile> result = new List<LibraryFile>();
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNodeList nodes = doc.SelectNodes($"/Libraries/Library[@Name='{name}']/Files/LibraryFile");
            if (nodes != null && nodes.Count > 0)
            {
                foreach (XmlNode node in nodes)
                {
                        LibraryFile libraryFile = new LibraryFile();
                        libraryFile.hash = node.Attributes["hash"].Value;
                        libraryFile.filename = node.SelectSingleNode("filename").InnerText;
                        libraryFile.filepath = node.SelectSingleNode("filepath").InnerText;
                        libraryFile.importdate = DateTime.Now;
                        if(node.SelectSingleNode("tags")!=null)
                            libraryFile.tags = Str2List(node.SelectSingleNode("tags").InnerText);
                        if (node.SelectSingleNode("descriptions") != null)
                            libraryFile.descriptions = node.SelectSingleNode("descriptions").InnerText;
                        result.Add(libraryFile);


                }
            }
            return result;
        }

        private static List<string> Str2List(string str)
        {
            if (str.IndexOf(";") > 0)
            {
                return str.Split(';').Where(arg => arg.Length > 0).ToList();
            }
            else if (str.Length > 0)
            {
                return new List<string>() { str };
            }

            return new List<string>();
        }


        public static void DeleteByName(string name)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNode x1 = doc.SelectSingleNode($"/Libraries/Library[@Name='{name}']");
            XmlElement root = doc.DocumentElement;
            if (x1 != null)
            {
                root.RemoveChild(x1);
                doc.Save(Settings.CurrentProject);
            }
        }

        public static void RemoveByName(string name, string hash)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNode x1 = doc.SelectSingleNode($"/Libraries/Library[@Name='{name}']/Files/LibraryFile[@hash='{hash}']");
            XmlNode xmlNode = doc.SelectSingleNode($"/Libraries/Library[@Name='{name}']/Files");
            if (xmlNode != null && x1 != null)
            {
                xmlNode.RemoveChild(x1);
                doc.Save(Settings.CurrentProject);
            }
        }


        public static void RenameLibrary(string oldname, string newname)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNode x1 = doc.SelectSingleNode($"/Libraries/Library[@Name='{oldname}']");
            if (x1 != null)
            {
                x1.Attributes["Name"].Value = newname;
                doc.Save(Settings.CurrentProject);
            }
        }

        public static void RenameFile(string libraryName, string hash, string newname, string newpath)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNode x1 = doc.SelectSingleNode($"/Libraries/Library[@Name='{libraryName}']/Files/LibraryFile[@hash='{hash}']/filename");
            XmlNode x2 = doc.SelectSingleNode($"/Libraries/Library[@Name='{libraryName}']/Files/LibraryFile[@hash='{hash}']/filepath");
            if (x1 != null && x2 != null)
            {
                x1.InnerText = newname;
                x2.InnerText = newpath;


                doc.Save(Settings.CurrentProject);
            }
        }

        public static void SaveLibraryFiles(string name, List<LibraryFile> libraryFiles)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNode x1 = doc.SelectSingleNode($"/Libraries/Library[@Name='{name}']");
            if (x1 != null)
            {
                //先创建 Files
                if (x1.SelectSingleNode("Files") == null) x1.AppendChild(doc.CreateElement("Files"));
                XmlNode files = x1.SelectSingleNode("Files");
                foreach (var lf in libraryFiles)
                {
                    if (files.SelectSingleNode($"LibraryFile[@hash='{lf.hash}']") == null)
                    {
                        //不存在该节点
                        XmlElement XE = doc.CreateElement("LibraryFile");
                        XE.SetAttribute("hash", lf.hash);
                        files.AppendChild(XE);
                    }

                    XmlNode LibraryFile = files.SelectSingleNode($"LibraryFile[@hash='{lf.hash}']");

                    //先创建节点
                    foreach (var node in LibraryFileNodes)
                    {
                        if (LibraryFile.SelectSingleNode(node) == null)
                        {

                            XmlElement XE = doc.CreateElement(node);
                            switch (node)
                            {
                                case "filename":
                                    XE.InnerText = lf.filename;
                                    break;
                                case "filepath":
                                    XE.InnerText = lf.filepath;
                                    break;
                                case "importdate":
                                    XE.InnerText = lf.importdate.ToString("yyyy-MM-dd HH:mm:ss");
                                    break;

                                case "tags":
                                    XE.InnerText = string.Join(";", lf.tags);
                                    break;

                                case "descriptions":
                                    XE.InnerText = lf.descriptions;
                                    break;
                                default:

                                    break;

                            }
                            LibraryFile.AppendChild(XE);
                        }
                    }
                }
                doc.Save(Settings.CurrentProject);
            }
        }


        public static void SaveLibraryFile(string name, LibraryFile libraryFile)
        {
            XmlDocument doc = new XmlDocument();
            doc.Load(Settings.CurrentProject);
            XmlNode x1 = doc.SelectSingleNode($"/Libraries/Library[@Name='{name}']");
            if (x1 != null)
            {
                //先创建 Files
                if (x1.SelectSingleNode("Files") == null) x1.AppendChild(doc.CreateElement("Files"));
                XmlNode files = x1.SelectSingleNode("Files");
                if (files.SelectSingleNode($"LibraryFile[@hash='{libraryFile.hash}']") == null)
                {
                    //不存在该节点
                    XmlElement XE = doc.CreateElement("LibraryFile");
                    XE.SetAttribute("hash", libraryFile.hash);
                    files.AppendChild(XE);
                }

                XmlNode LibraryFile = files.SelectSingleNode($"LibraryFile[@hash='{libraryFile.hash}']");
                
                foreach (var node in LibraryFileNodes)
                {
                    XmlNode xn = LibraryFile.SelectSingleNode(node);
                    bool isNull = false;
                    if(xn==null)
                    {
                        isNull = true;
                        xn = doc.CreateElement("LibraryFile");
                    }
                    switch (node)
                    {
                        case "filename":
                            xn.InnerText = libraryFile.filename;
                            break;
                        case "filepath":
                            xn.InnerText = libraryFile.filepath;
                            break;
                        case "importdate":
                            xn.InnerText = libraryFile.importdate.ToString("yyyy-MM-dd HH:mm:ss");
                            break;

                        case "tags":
                            xn.InnerText = string.Join(";", libraryFile.tags);
                            break;

                        case "descriptions":
                            xn.InnerText = libraryFile.descriptions;
                            break;
                        default:

                            break;

                    }
                    if(isNull)
                        LibraryFile.AppendChild(xn);

                }

                doc.Save(Settings.CurrentProject);
            }
        }
    }
}
